using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Tamir.IPLib;
using Tamir.IPLib.Packets;

namespace CommLayer
{
    public class UdpSniffer : StringComInt
    {
        string m_IPAddress;
        static int m_portUDP;
        protected static DelegateStringComNotifyData m_notificationDelegateUDP;
        TcpIpServer m_tcpServer;
        TcpIpClient m_tcpClient;
        PcapDevice m_device;
       

        /// <summary>
        /// Ip Address to call. Not implemented for this class
        /// </summary>
        public override string IPAddress 
        {
            get {
                Debug.Assert(false);
                return m_IPAddress; 
            }
            set {
                Debug.Assert(false);
                m_IPAddress = value; 
            }
        }


        public override bool IsConnected
        {
            get
            {
                return true;
            }

        }

        /// <summary>
        /// port to listen/call. 
        /// </summary>
        public override int Port
        {
            get {
                
                return m_portUDP; 
            } 
            set {
                
                m_portUDP = value;
            }
        }

        public override bool IsClient
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Sets the device to sniff on
        /// </summary>
        public PcapDevice Device
        {
            get {
                
                return m_device; 
            } 
            set {
                
                m_device = value;
            }
        }

 
        public UdpSniffer(PcapDevice device) 
        {
            Device = device;
        }

        ~UdpSniffer() 
        {
            Close();
        }

        /// <summary>
        /// Initialize the server (same initialization for client and server for this class)
        /// </summary>
        /// <param name="CallbackFunc"></param>
        public override void InitializeServer(DelegateStringComNotifyConnect connectCallbackFunc,
                                                DelegateStringComNotifyData dataCallbackFunc,
                                                DelegateStringComNotifyException exceptionCallbackFunc)
        {
            Initialize(connectCallbackFunc, dataCallbackFunc, exceptionCallbackFunc);
        }

        /// <summary>
        /// Initialize the client (same initialization for client and server for this class)
        /// </summary>
        /// <param name="CallbackFunc"></param>
        public override void InitializeClient(DelegateStringComNotifyConnect connectCallbackFunc,
                                                DelegateStringComNotifyData dataCallbackFunc,
                                                DelegateStringComNotifyException exceptionCallbackFunc)     
        {
            Initialize(connectCallbackFunc, dataCallbackFunc, exceptionCallbackFunc);
        }

        /// <summary>
        /// Initialize the sniffer to listen to Device and send output to callback function
        /// </summary>
        /// <param name="CallbackFunc"></param>
        public void Initialize(DelegateStringComNotifyConnect connectCallbackFunc,
                                                DelegateStringComNotifyData dataCallbackFunc,
                                                DelegateStringComNotifyException exceptionCallbackFunc)
        {
            // set only data. no connect (never) 
            // TODO: set exception handler for UDP
            m_notificationDelegateUDP = dataCallbackFunc;
            
            //Register our handler function to the 'packet arrival' event
            Device.PcapOnPacketArrival +=
                new SharpPcap.PacketArrivalEvent(device_PcapOnPacketArrival);

            //Open the device for capturing
            //false -- means non-promiscuous mode
            //10 -- means a read wait of 1000ms
            Device.PcapOpen(true, 10);

            //tcpdump filter to capture only TCP/IP packets			
            string filter = "udp";
            ////Associate the filter with this capture
            Device.PcapSetFilter(filter);

            //Start the capturing process
            Device.PcapStartCapture();
        }

	

        /// <summary>
        /// Not implemented for this class
        /// </summary>
        /// <param name="XMLString"></param>
        public override void SendString(string XMLString)
        {
            //do nada
            Debug.Assert(false);
        }

        /// <summary>
        /// Not implemented for this class
        /// </summary>
        /// <param name="XMLString"></param> 
        public override void SendStringAsync(string xmlString)
        {
            Debug.Assert(false);
        
        }

        /// <summary>
        /// Not implemented for this class
        /// </summary>
        /// <param name="XMLString"></param> 
        public override void QueueSendString(string xmlString)
        {
            Debug.Assert(false);

        }
        /// <summary>
        /// Stop capture
        /// </summary>
        public override void Close()
        {
            //Stop the capturing process
			Device.PcapStopCapture();
        }

        /// <summary>
		/// calls the notification delegate 
		/// </summary>
		private static void device_PcapOnPacketArrival(object sender, Packet packet)
		{

            int arrivingport  = (int)packet.Header[2] * 256 + (int)packet.Header[3];
            // filter out other sniffed packets
            if (m_portUDP != arrivingport)
                return; 
            
            int len = packet.PcapHeader.PacketLength;
            String bytes = (new System.Text.ASCIIEncoding()).GetString(packet.Data);
            m_notificationDelegateUDP(packet.PcapHeader.Date, bytes);
            //m_notificationDelegateUDP(packet.PcapHeader.Date, "Port: " + arrivingport + ". Len: " + len + ". Data: " + bytes);
		}   

    }
}
